package com.lry.basic.lucene;

import com.lry.basic.algorithm.trie.Trie;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.IntsRefBuilder;
import org.apache.lucene.util.fst.Builder;
import org.apache.lucene.util.fst.FST;
import org.apache.lucene.util.fst.PositiveIntOutputs;
import org.apache.lucene.util.fst.Util;
import java.io.IOException;
import java.util.*;

public class TestFst {

    int forNum = 100000;
    int dataNum = 10000;
    int wordMaxLen = 10;

    Random random = new Random();
    List<String> input = new ArrayList<>();
    String first;



    public static void main(String[] args) throws IOException {
        TestFst fst = new TestFst();

        fst.initData();
        //key存单词，value存记录的id，相当于一个倒排索引，先用单词查到id，再去数据库根据id查记录，有点像mysql二级索引
        fst.testFst();//fst, 前后缀树，时间复杂度基于查询字符串的长度，节省内存
        fst.testHashMap();//map一般情况都快于fst，trie，只是内存耗费过大
        fst.testTreeMap();
        fst.testTrie();////trie字典树, 前缀树，时间复杂度基于查询字符串的长度，节省内存
    }

    private void initData() {
        long start = System.currentTimeMillis();
        for(int i=0;i<dataNum;i++){
            input.add(randomString("abcdefghijklmnopqrstuvwxyz0123456789",wordMaxLen));
        }
        first = input.get(0);
        System.out.println("initData:"+(System.currentTimeMillis()-start)+"ms");

    }

    public String randomString(String baseString, int length) {
        StringBuilder sb = new StringBuilder(length);
        if (length < 1) {
            length = 1;
        }

        int baseLength = baseString.length();

        for(int i = 0; i < length; ++i) {
            int number = randomInt(baseLength);
            sb.append(baseString.charAt(number));
        }

        return sb.toString();
    }

    public int randomInt(int limit) {
        return random.nextInt(limit);
    }

    private void testFst() throws IOException {

        PositiveIntOutputs outputs = PositiveIntOutputs.getSingleton();

        Builder<Long> builder = new Builder(FST.INPUT_TYPE.BYTE1, outputs);

        IntsRefBuilder scratchInts = new IntsRefBuilder();

        for (String s : input) {
            BytesRef scratchBytes = new BytesRef(s);
            builder.add(Util.toIntsRef(scratchBytes, scratchInts), 1L);
        }
        FST<Long> fst = builder.finish();

        long start = System.currentTimeMillis();
        for(int i=0;i<forNum;i++){
            Long value = Util.get(fst, new BytesRef(first));
        }

        System.out.println("fst:"+(System.currentTimeMillis()-start)+"ms");
    }

    private void testTreeMap(){
        Map<String,Integer> map = new TreeMap<>();
        for (String inputValue : input) {
            map.put(inputValue,1);
        }

        long start = System.currentTimeMillis();
        for(int i=0;i<forNum;i++){
            map.get(first);
        }
        System.out.println("treemap:"+(System.currentTimeMillis()-start)+"ms");

    }

    private void testHashMap(){
        Map<String,Integer> map = new HashMap<>();
        for (String inputValue : input) {
            map.put(inputValue,1);
        }

        long start = System.currentTimeMillis();
        for(int i=0;i<forNum;i++){
            map.get(first);
        }
        System.out.println("hashmap:"+(System.currentTimeMillis()-start)+"ms");
    }

    private void testTrie() {
        Trie trie = new Trie();
        for (String inputValue : input) {
            trie.add(inputValue,1);
        }

        long start = System.currentTimeMillis();
        for (int i = 0; i < forNum; i++) {
            trie.getWeight(first);
        }
        System.out.println("trie:" + (System.currentTimeMillis() - start) + "ms");
    }

}
